Инструкция по созданию серверного приложения на nodejs + koa + postgresql

Koa - микрофреймфорк, разработанный командой разработчиков фреймворка Express, и призванный использовать самые последние стандарты языка JavaScript.
Koa “предлагает” активно использовать синтаксис async/await, который позволяет избавиться от ужасно нечитаемого “callback hell” и является более лучшей альтернативой Promise. Углубляться в синтаксис здесь не будем, это не тема статьи.
Сам Koa, являясь микрофреймворком, из коробки содержит только middleware систему, в нем даже нет маршрутизации. Все это можно получить, подключив необходимую функциональность в middleware chain.

Требования

Koa требует версию Node не меньше 7.6.0.
Использовать более старые версии можно, если подключить Babel, но тогда немного теряется посыл самого Koa (см. выше).
Версия PostgreSQL нас не интересует, поставим самую последнюю.

Подготовка среды

Про Node.js

Если Node не установлен, то вам необходимо сюда. Если же у вас еще и Linux или macOS, можно установить через менеджер пакетов - здесь сказано, как.
Чтобы проверить, что с Node все в порядке, можно набрать команду:

1
$ node --version

Она выведет текущую версию Node.
Также и про NPM:

1
$ npm --version

Установка зависимостей

Создайте директорию проекта, где будет храниться весь код. Откройте терминал и перейдите в данную директорию.

Инициализируем среду пакета:

1
$ npm init

NPM задаст несколько вопросов. Отвечаем хотя бы на имя пакета и имя автора.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
$ npm init

This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (ex) exampleapp
version: (1.0.0)
description: Example application on Koa and PostgreSQL
entry point: (index.js)
test command:
git repository:
keywords:
author: Nariman Safiulin <woofilee@gmail.com>
license: (ISC)
About to write to <..>\package.json:

{
"name": "exampleapp",
"version": "1.0.0",
"description": "Example application on Koa and PostgreSQL",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Nariman Safiulin <woofilee@gmail.com>",
"license": "ISC"
}


Is this ok? (yes)

У нас должен был появиться файл package.json.

Поставим koa:

1
$ npm i koa

Также поставим что-то для роутинга запросов. Будем использовать koa-router, как самый популярный и полнофункциональный вариант.
И заодно koa-logger, чтобы видеть наши запросы на сервер в терминале.

1
$ npm i koa-router koa-logger

Для общения с базой будем использовать пакет node-postgres. Это не ORM, а обычный драйвер с необходимой функциональностью. Его достаточно для микросервисов.

1
$ npm i pg

PostgreSQL

Скачать установщик PostgreSQL можно отсюда. Там же есть и уже и готовые бинарники в архиве, чтобы ничего не устанавливать, а просто распаковать, и имена пакетов для пакетных менеджеров.
Чтобы проверить, что все установилось верно, можно набрать команду:

1
$ sudo -u postgres psql

Или на Windows (если не создавали базу вручную, введите свое имя пользователя вместо стандартного postgres):

1
> psql -U postgres

На Linux и macOS, как правило, база уже будет запущена сама.
На Windows же нужно все включить с пинка:

1
2
3
> initdb -U postgres -D data
> pg_ctl -D data start
> psql -U postgres

Здесь postgres - это имя пользователя, лучше его указать по умолчанию, для начала, а data - директория, где будут храниться базы, можно указать любую удобную.
После чего pg_ctl запускает PostgreSQL (с указанием директории с базами).

По окончанию, мы должны увидеть приветственную консоль:

1
postgres=#

Выйти из нее можно, набрав \q.

По умолчанию за нас будет создана база postgres. Нам этого достаточно для целей этого туторила.

Hello, World!

Создадим файл app.js, и заполним его немного измененным стандартным примером Koa. Из кода достаточно все понятно.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const Koa = require('koa');
const Router = require('koa-router');
const Logger = require('koa-logger');

const app = new Koa();
const router = new Router();

// Отвечаем миру на GET запросы
router.get('/', async (ctx) => {
ctx.body = 'Hello, World!\n';
});

// Отвечаем на имя на GET запросы. :name здесь - это часть URL, и является аргументом
router.get('/:name', async (ctx) => {
ctx.body = `Hello, ${ctx.params.name}!\n`;
});

// Логгер
app.use(Logger());
// Добавим все роуты. Второй middleware отвечает на OPTIONS запросы.
app.use(router.routes()).use(router.allowedMethods());

// Слушаем порт, запускаем сервер
app.listen(3000, () => {
console.log('Server running on port 3000');
});

Теперь можно запустить сервер:

1
$ node app.js

Если сервер успешно запустился, то можно зайти в браузер, и в адресной строке перейти по адресу http://localhost:3000/. Мы должны увидеть приветствие. Также, если к адресу добавить имя, т.е. н-р http://localhost:3000/Nariman, мы должны увидеть свое имя в ответе.
В терминале мы должны увидеть примерно такую картину:

1
2
3
4
5
6
7
8
9
10
11
$ node app.js

Server running on port 3000
<-- GET /
--> GET / 200 13ms 14b
<-- GET /favicon.ico
--> GET /favicon.ico 200 7ms 20b
<-- GET /Nariman
--> GET /Nariman 200 10ms 16b
<-- GET /favicon.ico
--> GET /favicon.ico 200 7ms 20b

Теперь свяжемся с базой.
Мы будем сразу же использовать пул, а не отдельные подключения. Это распространенная практика, тем более для PostgreSQL. Пул позволяет хранить несколько соединений, тем самым не тратя время на их создание и не заниматься их менеджементом.

Добавим зависимость:

1
const { Pool } = require('pg');

Перед запуском сервера, добавим код подключения к базе.

1
2
3
4
5
6
7
app.pool = new Pool({
user: 'postgres',
host: 'localhost',
database: 'postgres',
password: '', // По умолчанию пароля нет
port: 5432, // Порт по умолчанию
});

Немного изменим наши роуты, чтобы совершить запрос к базе.

1
2
3
4
5
6
7
8
9
router.get('/', async (ctx) => {
const { rows } = await ctx.app.pool.query('SELECT $1::text as message', ['Hello, World!'])
ctx.body = rows[0].message;
});

router.get('/:name', async (ctx) => {
const { rows } = await ctx.app.pool.query('SELECT $1::text as message', [`Hello, ${ctx.params.name}!`])
ctx.body = rows[0].message;
});

Сразу заметим, что Koa умеет преобразовывать результат в JSON, если в качестве ответа вернуть не строку. Если вернуть просто rows, мы увидим JSON ответ.

Можно перезапустить сервер и увидеть результат.

Вместо заключения

Мы написали все в одном файле. Конечно же, уже для реального проекта, нужно составить правильную архитектуру проекта, а также позаботиться о закрытии пула PostgreSQL и соединений к Koa при выключении сервера.

В качестве инструмента для общения с базой можно использовать такие библиотеки, как Sequelize, Bookshelf, Massive, и другие.